package com.jvup.common.widget.snackbar;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.ColorStateList;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import android.widget.TextView;

import androidx.annotation.ColorInt;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.coordinatorlayout.widget.CoordinatorLayout;

import com.jvup.common.R;
import com.jvup.common.widget.animation.AnimationUtils;

import static com.jvup.common.widget.snackbar.BaseTransientBar.LifeStateChangeCallback.DISMISS_EVENT_ACTION;

public final class SnackBar extends BaseTransientBar<SnackBar> {

    private static ViewGroup findSuitableParent(View view) {
        ViewGroup fallback = null;

        do {
            if (view instanceof CoordinatorLayout) {
                return (ViewGroup)view;
            }

            if (view instanceof FrameLayout) {
                if (view.getId() == android.R.id.content) {
                    return (ViewGroup)view;
                }

                fallback = (ViewGroup)view;
            }

            if (view != null) {
                ViewParent parent = view.getParent();
                view = parent instanceof View ? (View)parent : null;
            }
        } while(view != null);

        return fallback;
    }

    @NonNull
    public static SnackBar make(@NonNull View view, @NonNull CharSequence text, int duration,@LayoutRes int layoutRid) {
        ViewGroup parent = findSuitableParent(view);
        if (parent == null) {
            throw new IllegalArgumentException("No suitable parent found from the given view. Please provide a valid view.");
        } else {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            SnackBarContentLayout content = (SnackBarContentLayout)inflater.inflate(layoutRid, parent, false);
            SnackBar snackbar = new SnackBar(parent, content, content);
            snackbar.setText(text);
            snackbar.setDuration(duration);
            return snackbar;
        }
    }

    @NonNull
    public static SnackBar make(@NonNull View view, @NonNull CharSequence text, int duration) {
        return make(view, text, duration,R.layout.design_layout_snackbar_include);
    }

    @NonNull
    public static SnackBar make(@NonNull View view, @StringRes int resId, int duration,@LayoutRes int layoutRid) {
        return make(view, view.getResources().getText(resId), duration,layoutRid);
    }

    @NonNull
    public static SnackBar make(@NonNull View view, @StringRes int resId, int duration) {
        return make(view, view.getResources().getText(resId), duration);
    }

    //--------------------------------------------以下是SnackBar实体实现内容-------------------------------------------------
    private final AccessibilityManager accessibilityManager;
    private final ContentViewCallback contentViewCallback;
    private boolean hasAction;

    private SnackBar(ViewGroup parent, View content, ContentViewCallback contentViewCallback) {
        super(parent, content);
        if (contentViewCallback == null) {
            throw new IllegalArgumentException("Transient bar must have non-null callback");
        }
        this.contentViewCallback = contentViewCallback;
        this.accessibilityManager = (AccessibilityManager)parent.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
    }

    @Override
    public void show() {
        super.show();
    }

    @Override
    public void dismiss() {
        super.dismiss();
    }

    @Override
    public boolean isShown() {
        return super.isShown();
    }

    @Override
    public int getDuration() {
        return this.hasAction && this.accessibilityManager.isTouchExplorationEnabled() ? LENGTH_INDEFINITE : super.getDuration();
    }

    @Override
    void animateViewIn() {
        FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) this.view.getLayoutParams();
        SceneAnimate sceneAnimate = Gravity.TOP == layoutParams.gravity ? AnimationUtils.snackBarTopAnimation : AnimationUtils.snackBarBottomAnimation;
        Animator animator = sceneAnimate.animateViewIn(this.view);
        animator.setDuration(ANIMATION_DURATION);
        animator.addListener(new AnimatorListenerAdapter() {
            public void onAnimationStart(Animator animator) {
                contentViewCallback.animateContentIn(70, ANIMATION_FADE_DURATION);
            }

            public void onAnimationEnd(Animator animator) {
                onViewShown();
            }
        });
        animator.start();
    }

    @Override
    void animateViewOut(final int event) {
        FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) this.view.getLayoutParams();
        SceneAnimate sceneAnimate = Gravity.TOP == layoutParams.gravity ? AnimationUtils.snackBarTopAnimation : AnimationUtils.snackBarBottomAnimation;
        Animator animator = sceneAnimate.animateViewOut(this.view);
        animator.setDuration(ANIMATION_DURATION);
        animator.addListener(new AnimatorListenerAdapter() {
            public void onAnimationStart(Animator animator) {
                contentViewCallback.animateContentOut(0, ANIMATION_FADE_DURATION);
            }

            public void onAnimationEnd(Animator animator) {
                onViewHidden(event);
            }
        });
        animator.start();
    }

    public SnackBar setGravity(int gravity){
        FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) this.view.getLayoutParams();
        layoutParams.gravity = gravity;
        return this;
    }

    @NonNull
    public SnackBar setText(@NonNull CharSequence message) {
        SnackBarContentLayout contentLayout = (SnackBarContentLayout)this.view.getChildAt(0);
        TextView tv = contentLayout.getMessageView();
        tv.setText(message);
        return this;
    }

    @NonNull
    public SnackBar setText(@StringRes int resId) {
        return this.setText(this.getContext().getText(resId));
    }

    @NonNull
    public SnackBar setAction(@StringRes int resId, View.OnClickListener listener) {
        return this.setAction(this.getContext().getText(resId), listener);
    }

    @NonNull
    public SnackBar setAction(CharSequence text, final View.OnClickListener listener) {
        SnackBarContentLayout contentLayout = (SnackBarContentLayout)this.view.getChildAt(0);
        TextView tv = contentLayout.getActionView();
        if (!TextUtils.isEmpty(text) && listener != null) {
            this.hasAction = true;
            tv.setVisibility(View.VISIBLE);
            tv.setText(text);
            tv.setOnClickListener(view -> {
                listener.onClick(view);
                SnackBar.this.dispatchDismiss(DISMISS_EVENT_ACTION);
            });
        } else {
            tv.setVisibility(View.GONE);
            tv.setOnClickListener(null);
            this.hasAction = false;
        }

        return this;
    }

    @NonNull
    public SnackBar setActionTextColor(ColorStateList colors) {
        SnackBarContentLayout contentLayout = (SnackBarContentLayout)this.view.getChildAt(0);
        TextView tv = contentLayout.getActionView();
        tv.setTextColor(colors);
        return this;
    }

    @NonNull
    public SnackBar setActionTextColor(@ColorInt int color) {
        SnackBarContentLayout contentLayout = (SnackBarContentLayout)this.view.getChildAt(0);
        TextView tv = contentLayout.getActionView();
        tv.setTextColor(color);
        return this;
    }

    @NonNull
    public <V extends View> SnackBar updateViewAttribute(@IdRes int viewRid, ViewAttribute<V> viewAttribute) {
        viewAttribute.<V>update(this.view.findViewById(viewRid));
        return this;
    }

    /**
     * 场景动画
     */
    public interface SceneAnimate {

        /**
         * 提示入场动画
         * @param view snack根布局
         */
        @NonNull
        Animator animateViewIn(View view);

        /**
         * 提示退场动画
         * @param view snack根布局
         */
        @NonNull
        Animator animateViewOut(View view);

    }

    /**
     * 控件属性更新
     * @param <V> 目标控件类型
     */
    public interface ViewAttribute<V extends View> {
        void update(V view);
    }

}